package com.gpStudy.Netty.IO.BIO.tomcat_netty;


import com.gpStudy.Netty.IO.BIO.tomcat_netty.http.GPRequest;
import com.gpStudy.Netty.IO.BIO.tomcat_netty.http.GPResponse;
import com.gpStudy.Netty.IO.BIO.tomcat_netty.http.GPServlet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/*
    //J2EE 标准
    //Servlet
    //Request
    //Response


    1、配置启动端口，默认 8080， ServerSeockt   IP:localhost
    2. 配置web.xml 自己写的 serrlet 继承 HttpServlet
          servlet-name
          servlet-class
          url-pattern

    3. 读取配置，url-pattern 和 servlet 建立一个映射关系
          Map  servletMapping


    4. Http请求，发送的数据就是 字符串，有规律的
          从浏览器的控制台请求中可以看出，请求头的信息  其实也是一段固定格式的字符串


     5.从协议内容中拿到 URL，把相依的 servlet 用反射进行实例化

     6. 调用实例化对象的service()方法，执行具体的逻辑 doGet()/doPost() 方法
     7. Request（InputStream）/ Response(OutputStream)
 */
public class GPTomcat {

    private int port = 8080;

    private ServerSocket server;

    private Map<String, GPServlet> servletMapping = new HashMap<>();

    private Properties webxml = new Properties();

    public void init(){

        try {

            String WEB_INF = this.getClass().getResource("/").getPath();
            FileInputStream fis = new FileInputStream(WEB_INF + "web_netty.properties");

            webxml.load(fis);

            for (Object k : webxml.keySet()){
                String key = k.toString();
                if (key.endsWith(".url")) {
                    String url = webxml.getProperty(key);
                    String serverName = key.replaceAll("\\.url$", "");
                    String className = webxml.getProperty(serverName + ".className");

                    GPServlet gpServlet = (GPServlet) Class.forName(className).newInstance();
                    servletMapping.put(url, gpServlet);

                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    public void start(){

        init();
        // Netty 封装了 NIO， Reactor 模型， Boss  worker
        // Boss 线程
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // Worker 线程
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // Netty 服务
            // ServerBootstrap   ServerSocketChannel
            ServerBootstrap server = new ServerBootstrap();

            // 链路式编程
            server.group(bossGroup, workerGroup)
                    // 主线程处理类，看到这样的写法，底层就是用的反射
                    .channel(NioServerSocketChannel.class)
                    // 子线程处理类 ， Handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 客户端初始化处理
                        protected void initChannel(SocketChannel socketChannel) throws Exception {

                            socketChannel.pipeline().addLast(new HttpResponseEncoder());
                            socketChannel.pipeline().addLast(new HttpRequestDecoder());

                            socketChannel.pipeline().addLast(new GPTomcatHandler());
                        }
                    })
                    // 针对主线程的配置  分配线程最大数量  128
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 针对子线程的配置  保持长连接
                    .option(ChannelOption.SO_KEEPALIVE, true);
            ChannelFuture f = server.bind(port).sync();

            System.out.println("GPTomcat 已启动，监听的端口是：" + port);

            f.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {

            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public class GPTomcatHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void  channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
            if (msg instanceof HttpRequest) {

                HttpRequest req = (HttpRequest) msg;
                // 转交给我们自己的 request 实现
                GPRequest gpRequest = new GPRequest(ctx, req);
                // 转交给我们自己的 response 实现
                GPResponse gpResponse = new GPResponse(ctx, req);

                String url = req.uri();

                if (servletMapping.containsKey(url)) {
                    servletMapping.get(url).service(gpRequest,gpResponse);
                }else{
                    gpResponse.write("404 - Not Found");
                }
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        }
    }

    public static void main(String[] args) {
        new GPTomcat().start();
    }
}
